/*
 * HttpManager.java
 *
 * Copyright (c) 2006 LightPole, Inc.
 * All rights reserved.
 *
 * No part of this source code may be copied, userd, or modified
 * without the express written consent of LightPole, Inc.
 *
 * Created on July 15, 2006, 3:08 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package com.rytong.tools.httpconnect;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
import android.app.Activity;
import com.rytong.tools.clienthello.ClientHello;
import com.rytong.tools.crypto.Base64;
import com.rytong.tools.crypto.HMac;
import com.rytong.tools.ui.BaseView;
import com.rytong.tools.utils.Utils;

/**
 * Manager of HTTP connections.
 */
public class HttpManager {
    public HttpURLConnection hc_;
    // 项目名称
    static public String APPNAME;
    static public String OPLATFORM;
    static public boolean isTimeout;
    static public boolean isAppUpgrading; //服务器 升级状态
    public int responseCode_;
    public boolean isReachable_;
    String errorStr;
    String errorType;
    String errorContent;
    // 防重放统计参数
    static public long serialN_ = 0;
    private Stack headName_;
    private Stack headValue_;
    public final static char MATCH = '\"';
    /**
     * Used for gzip. Re. rfc1951.
     */
    static int gIndex = 0;
    static int bitByte = 0;
    static int bitIndex = 0;
    private static final int MAX_BITS = 16;
    private static final int[] EXTRA_L_BITS = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
            5, 5, 5, 5, 0 };

    private static final int[] EXTRA_L_VALUES = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51,
            59, 67, 83, 99, 115, 131, 163, 195, 227, 258 };
    private static final int[] EXTRA_D_BITS = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
            10, 11, 11, 12, 12, 13, 13 };
    private static final int[] EXTRA_D_VALUES = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
            513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 };
    private static final int[] DYNAMIC_L_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
    public final static String POST = "POST";
    public final static String GET = "GET";
    private String httpconnectType_ = POST;
    // private ApnGateway apn_;
    public static final String MIME_ARC = "application/octet-stream";
    public static final String MIME_JSON = "application/json";
    public static String COOKIE;
    // int isCMWAP_ = 0; // Notes: 0: default(cmwap), 1: cmnet, 2: cmwap.
    public static int CONNECTYPE; // 0-CMNET; 1-CMWAP.
    boolean isGetWML_ = false;
    final String cancel_ = "取消";
    private Activity activity_;

    // XXX This belongs to a Util package.
    public static final class EmptyResultException extends Exception {
        public EmptyResultException(String s) {
            super(s);
        }
    }

    public static final class NoGatewayException extends Exception {
        public NoGatewayException(String s) {
            super(s);
        }
    }

    // When we do cancel throw this exception.
    public static final class CancelIOException extends IOException {
        public CancelIOException(String s) {
            super(s);
        }
    }

    // When we do cancel throw this exception.
    public static final class VerifyException extends IOException {
        public VerifyException(String s) {
            super(s);
        }
    }

    public HttpManager(Activity activity) {
        activity_ = activity;
        headName_ = new Stack();
        headValue_ = new Stack();
    }

    /**
     * @param url
     * @param task
     * @return
     * @throws Exception
     * @throws NoGatewayException
     */
    public String sendRequest(String url, WaitDialog.Task task) throws Exception, NoGatewayException {
        isGetWML_ = false;
        Object resultObj = sendHttpRequest(url, null, GET, null, null, null,task);
        String result = null;
        if (resultObj != null && resultObj instanceof String) {
            result = (String) resultObj;
        }
        return result;
    }

    /**
     * @param url
     * @param requestBody
     * @param task
     * @param contentType
     *            TODO
     * @param accept
     *            TODO
     * @return
     * @throws Exception
     * @throws NoGatewayException
     */
    public Object sendPostRequest(String url, String requestBody, WaitDialog.Task task, String contentType,
            String accept,Map<String,String> headers) throws NoGatewayException, Exception {
        isGetWML_ = false;
        Object resultObj = null;
        resultObj = sendHttpRequest(url, requestBody, httpconnectType_, contentType, accept,headers, task);
        return resultObj;
    }

    /**
     * @param url
     * @param requestBody
     * @param task
     * @param contentType
     *            TODO
     * @param accept
     *            TODO
     * @return
     * @throws Exception
     * @throws NoGatewayException
     */
    public Object sendPostRequest(String url, Object requestBody, WaitDialog.Task task, String contentType,
            String accept) throws NoGatewayException, Exception {
        isGetWML_ = false;

        Object resultObj = null;
        if (requestBody == null) {
            resultObj = sendHttpRequest(url, null, GET, null, null,null, task);
        } else {
            resultObj = sendHttpRequest(url, requestBody, POST, contentType, accept,null, task);
        }
        return resultObj;
    }

    /**
     * @param url
     * @param requestStr
     * @param task
     * @return
     * @throws Exception
     * @throws NoGatewayException
     */
    public String sendPostRequestWML(String url, String requestStr, WaitDialog.Task task) throws Exception,
            NoGatewayException {
        isGetWML_ = true;
        Object resultObj = null;
        String wml = null;
        resultObj = sendHttpRequest(url, requestStr, httpconnectType_, null, null,null, task);
        if (resultObj != null && resultObj instanceof String) {
            wml = (String) resultObj;
            if (wml != null && wml.indexOf("name=\"SIGN\"") == -1) {
                // 没有手机签名字段�?
                resultObj = sendHttpRequest(url, requestStr, httpconnectType_, null, null, null,task);
                if (resultObj != null && resultObj instanceof String) {
                    wml = (String) resultObj;
                }
            }
            isGetWML_ = false;
        }
        return wml;
    }

    // Get a code from data.
    private static int getCode(byte data[], int tree[]) {
        int node = tree[0];
        while (node >= 0) {
            if (bitIndex == 0)
                bitByte = (data[gIndex++] & 0xFF);
            node = (((bitByte & (1 << bitIndex)) == 0) ? tree[node >> 16] : tree[node & 0xFFFF]);
            bitIndex = (bitIndex + 1) & 0x7;
        }
        return (node & 0xFFFF);
    }

    // get num bits from data. the num should not bigger than 32.
    private int getBits(byte[] data, int num) {
        int result = 0;
        int i = 0;
        if (bitIndex != 0) {
            i = 8 - bitIndex;
            result = bitByte >> bitIndex;
        }
        while (i < num) {
            bitByte = data[gIndex++] & 0xFF;
            result |= (bitByte << i);
            i += 8;
        }
        bitIndex = (bitIndex + num) & 0x7;// calculate (bitIndex + num)%8
        result &= (0xffffffff >>> (32 - num));
        return result;
    }

    // Decompress the literal/length code and the distance code.
    private byte[] decompressCode(byte data[], int blTree[], int count) {
        int code = 0;
        byte previousCode = 0;
        int times = 0; // The number of the previous code's length need to
        // repeat.
        byte treeBits[] = new byte[count];
        int index = 0;
        while (index < count) {
            code = getCode(data, blTree);
            if (code == 16) {
                times = getBits(data, 2) + 3;
            } else if (code == 17) {
                times = getBits(data, 3) + 3;
                previousCode = 0;
            } else if (code == 18) {
                times = getBits(data, 7) + 11;
                previousCode = 0;
            } else {
                times = 0;
                previousCode = (byte) code;
                treeBits[index++] = (byte) code;
            }
            for (int i = 0; i < times; i++) {
                treeBits[index++] = previousCode;
            }
        }
        return treeBits;
    }

    // Get a huffman tree.
    private static int[] huffmanTree(byte bits[]) {
        int bl_count[] = new int[MAX_BITS + 1];
        for (int i = 0; i < bits.length; i++) {
            bl_count[bits[i]]++;
        }
        int code = 0;
        bl_count[0] = 0;
        int next_code[] = new int[MAX_BITS + 1];
        // Count the number of codes for each code length.
        for (int i = 1; i <= MAX_BITS; i++) {
            code = (code + bl_count[i - 1]) << 1;
            next_code[i] = code;
        }
        int tree[] = new int[((bits.length - 1) << 1) + MAX_BITS];
        int treeInsert = 1;
        for (int i = 0; i < bits.length; i++) {
            int len = bits[i];
            if (len != 0) {
                code = next_code[len]++;
                int node = 0;
                for (int bit = len - 1; bit >= 0; bit--) {
                    int value = code & (1 << bit);
                    if (value == 0) {
                        int left = tree[node] >> 16;
                        if (left == 0) {
                            tree[node] |= (treeInsert << 16);
                            node = treeInsert++;
                        } else
                            node = left;
                    } else {
                        int right = tree[node] & 0xFFFF;
                        if (right == 0) {
                            tree[node] |= treeInsert;
                            node = treeInsert++;
                        } else
                            node = right;
                    }
                }
                tree[node] = 0x80000000 | i;
            }
        }
        return tree;
    }

    // It's used to decompress gzip data. Re. rfc1951 and rfc 1952.
    public byte[] gunzip(byte[] gzipData) throws IOException {
        // Check if the data is gzip format and if it is used "deflate"
        // compression method.
        if (gzipData[0] != 31 || gzipData[1] != -117)
            throw new IOException("压缩数据格式错误!");
        if (gzipData[2] != 8)
            throw new IOException("压缩数据方法错误");

        // Skip the gzip data header.
        byte flg = gzipData[3];
        gIndex = 10;
        bitIndex = 0;
        bitByte = 0;
        if ((flg & 4) != 0)
            gIndex += getBits(gzipData, 16);
        if ((flg & 8) != 0)
            while (gzipData[gIndex++] != 0)
                ;
        if ((flg & 16) != 0)
            while (gzipData[gIndex++] != 0)
                ;
        if ((flg & 2) != 0)
            gIndex += 2;

        int temp = gIndex;
        gIndex = gzipData.length - 4;
        // The size of the original input data
        int size = getBits(gzipData, 16) | (getBits(gzipData, 16) << 16);
        byte[] unzipData = new byte[size];
        gIndex = temp;

        int unzipIndex = 0;
        bitIndex = 0;
        bitByte = 0;
        int lastBlock = 0; // 0 indicates have more block when 1 indicates it is
        // the last block.
        int type = 0;// 0 indicates uncompress data, 1 indicates use static
        // Huffman, 2 indicates use dynamic Huffman.
        while (lastBlock == 0) {
            lastBlock = getBits(gzipData, 1);
            type = getBits(gzipData, 2);
            if (type == 0) {
                // uncompress data
                bitIndex = 0;
                int length = getBits(gzipData, 16);
                gIndex += 2;
                System.arraycopy(gzipData, gIndex, unzipData, unzipIndex, length);
                gIndex += length;
                unzipIndex += length;
            } else {
                byte[] lBits;
                byte[] dBits;
                if (type == 1) {
                    // use static huffman.
                    lBits = new byte[288];// The lTree node numbers 286, the
                    // last two nodes is use for full
                    // tree.
                    for (int i = 0; i < 288; i++) {
                        if (i < 144 || i > 279) {
                            lBits[i] = 8;
                        } else if (i < 256) {
                            lBits[i] = 9;
                        } else {
                            lBits[i] = 7;
                        }
                    }
                    dBits = new byte[32];// The dTree node numbers 30, the last
                    // two nodes is use for full tree.
                    for (int i = 0; i < dBits.length; i++) {
                        dBits[i] = 5;
                    }
                } else if (type == 2) {
                    // use dynamic huffman.
                    int hlit = getBits(gzipData, 5) + 257;
                    int hdist = getBits(gzipData, 5) + 1;
                    int hclen = getBits(gzipData, 4) + 4;
                    byte[] bltreeBits = new byte[19];// The blTree node numbers
                    // 19.
                    for (int i = 0; i < hclen; i++)
                        bltreeBits[DYNAMIC_L_ORDER[i]] = (byte) getBits(gzipData, 3);
                    int[] blTree = huffmanTree(bltreeBits);
                    lBits = decompressCode(gzipData, blTree, hlit);
                    dBits = decompressCode(gzipData, blTree, hdist);
                } else {
                    throw new IOException("不能正确解压数据.");
                }

                int[] lTree = huffmanTree(lBits);// The literal/length tree.
                int[] dTree = huffmanTree(dBits);// The distance tree.
                int code = 0;
                while ((code = getCode(gzipData, lTree)) != 256) {// code=256
                    // indicates
                    // the end
                    // of this
                    // block.
                    if (code < 256) {// literal byte
                        unzipData[unzipIndex++] = (byte) code;
                    } else {// length/distance pairs
                        code -= 257;
                        int length = EXTRA_L_VALUES[code];
                        if (EXTRA_L_BITS[code] > 0)
                            length += getBits(gzipData, EXTRA_L_BITS[code]);
                        code = getCode(gzipData, dTree);
                        int distance = EXTRA_D_VALUES[code];
                        if (EXTRA_D_BITS[code] > 0)
                            distance += getBits(gzipData, EXTRA_D_BITS[code]);
                        while (distance < length) {
                            System.arraycopy(unzipData, unzipIndex - distance, unzipData, unzipIndex, distance);
                            unzipIndex += distance;
                            length -= distance;
                        }
                        System.arraycopy(unzipData, unzipIndex - distance, unzipData, unzipIndex, length);
                        unzipIndex += length;
                    }
                }
            }
        }
        return unzipData;
    }

    /**
     * Parse simple state response XMLs from server and retrieve attributes from it. Used by UserManager, PoiRepository
     * (add/remove POI), etc.
     */
    public String getXMLResponseAttribute(String reply, String attr, int startIndex, char matchCh) {
        int start = reply.indexOf(attr, startIndex);
        if (start < 0)
            return null;
        start += attr.length();
        int end = reply.indexOf(matchCh, start);
        if (end > start) {
            String s = reply.substring(start, end);
            return s;
        }
        return null;
    }

    /**
     * @param url
     * @param requestBody
     * @param method
     * @param contentType
     * @param accept
     * @param task
     * @return
     * @throws Exception
     * @throws NoGatewayException
     */
    public Object sendHttpRequest(String url, Object requestBody, String method, String contentType, String accept)
            throws Exception, NoGatewayException {
    	if(!Utils.isConnectByNet()){
    		throw new Exception("当前网络不可用，请稍后再试!");
    	}
        OutputStream dos = null;
        InputStream dis = null;
        // InputStreamReader dir = null;
        Object resultObj = null;
        String result = null;
        String encrypted = null;
        errorStr = null;
        errorType = null;
        errorContent = null;

        url = addHead(url);
        Utils.printOutToConsole("url-->" + url);
        try {
            // 修正防重放功能限制条件，只有通过加密通道以后才能执行防重放

            if (!url.contains(ClientHello.CLIENT_KEY_EXCHANGE) && !url.contains(ClientHello.CLIENT_FACILITY_HELLO)
                    && !url.contains(ClientHello.CLIENT_HELLO)
                    && (ClientHello.getText() != null && !ClientHello.getText().equals(""))) {
                if (requestBody instanceof String) {
                    requestBody = addSerialNData((String) requestBody);
                }
            }

            String ct = null;
            int respCode = 0;
            // 这里最多尝试两次，两次后即使还是移动收费提示页我们也返回。对于取wml内容�? 此处不处理，取完内容后再处理�?
            // 在这里不比较是否是使用cmwap接入点，考虑到有些手机使用直连也能通过cmwap, 但却得到收费提示页�?
            int times = 2;
            do {
                times--;
                try {
                    if (dos != null)
                        dos.close();
                    if (hc_ != null)
                        hc_.disconnect();
                } catch (IOException ignored) {
                    Utils.printException(ignored);
                }
                hc_ = getOpenedConnection(url, method, contentType, accept, requestBody);

                // Send the string entered by user byte by byte
                if (requestBody != null) {
                    byte[] body = null;
                    if (requestBody instanceof String) {
                        body = ((String) requestBody).getBytes("UTF-8");
                    } else {
                        body = (byte[]) requestBody;
                    }
                    hc_.setRequestProperty("Content-Length", "" + body.length);
                    // 允许output操作
                    hc_.setDoOutput(true);
                    dos = hc_.getOutputStream();
                    dos.write(body);
                } else {
                    hc_.setRequestProperty("Content-Length", "0");
                }
                respCode = hc_.getResponseCode();
                responseCode_ = respCode;
                Utils.printOutToConsole("ResponseCode--->" + respCode);
                if (respCode != HttpURLConnection.HTTP_OK) {
                    throw new NoGatewayException("无法连接服务器！");
                }
                ct = hc_.getHeaderField("Content-Type");
            } while (times > 0 && !isGetWML_ && ct != null
                    && (ct.indexOf("text/vnd.wap.wml") != -1 || ct.indexOf("application/vnd.wap.wmlc") != -1));

            // 允许使用input
            // hc.setDoInput(true);待议，该方法同一个对象只要调用一次即可，调用多次会引发异常�?
            dis = hc_.getInputStream();
            long len = hc_.getContentLength(); // we can't use dis.available().
            ByteArrayOutputStream buffer = new ByteArrayOutputStream(1024);
            readByByte(dis, -1, buffer);
            byte[] resultByts = buffer.toByteArray();
            buffer.close();
            // unZip the result.
            String gzip = hc_.getHeaderField("Content-Encoding");
            if (gzip == null) {
                gzip = "not gzip";
            }
            Utils.printOutToConsole("encodeing gzip---->" + gzip);
            if (gzip != null && gzip.equals("gzip")) {
                resultByts = Utils.gunzip(resultByts);
            }
//            if (resultByts != null && ClientHello.serverHmacKey_ != null) {
//                byte[] hmacData = HMac.encryptHMAC(resultByts, ClientHello.serverHmacKey_, HMac.KEY_MAC_SHA1);
//                String orgHmac = Base64.encode(hmacData);
//                String digHmac = hc_.getHeaderField("X-Emp-Signature");
//                if (null != digHmac && digHmac.equalsIgnoreCase("timeout")) {
//                    // 此处超时界面取用本地报文
//                    result = Utils.getStringFormAsset(activity_, "timeout.txt");
//                    // 当该头属性包含文字是超时信息时，不显示hmac错误
//                }else if (digHmac == null || !digHmac.equals(orgHmac)) {
//                    throw new VerifyException("数据接收不完整，请重试！");
//                }
//            }

            Utils.printOutToConsole("response Content-Type ---> " + ct);
            if (ct.equals(MIME_ARC)) {
                resultObj = resultByts;
            } else {
                result = new String(resultByts, "UTF-8").trim();
                resultObj = result;
            }
        } catch (SocketTimeoutException cancel) {// cancel时不要再向外throws.
        	 throw new SocketTimeoutException("网络繁忙，请稍后重试!");   
        } catch (CancelIOException cancel) {// cancel时不要再向外throws.
            Utils.printException(cancel);
        } catch (VerifyException ve) {
            throw ve;
        } catch (SecurityException se) {
            throw new NoGatewayException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
        } catch (ConnectException cf) {
            Utils.printException(cf);
            throw new IOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
        } catch (Exception ioe) {
            Utils.printException(ioe);
            if (ioe.getMessage() != null && ioe.getMessage().toLowerCase().indexOf("hmac") != -1) {
                throw new IOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
            }
        } catch (Error err) {
            Utils.printOutToConsole(err.toString());
            throw new Exception(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
        } finally {
            // Free up i/o streams and http connection
            try {
                // if (dir != null) dir.close();
                if (dis != null)
                    dis.close();
                if (dos != null)
                    dos.close();
                if (hc_ != null)
                    hc_.disconnect();
            } catch (IOException ignored) {
                Utils.printException(ignored);
            }
        }

        if (null != result && result.indexOf("<error") != -1) {
//            String error = Utils.getXMLResponseAttribute(result, "string=\"", 0, Utils.MATCH);
//
//            errorStr = error;
//            errorType = Utils.getXMLResponseAttribute(result, "type=\"", 0, Utils.MATCH);
//            errorContent = Utils.getXMLResponseAttribute(result, "content=\"", 0, Utils.MATCH);
            throw new Exception(result);
        }
        return resultObj;

    }

    private void readByByte(InputStream dis, long len, ByteArrayOutputStream buffer) throws IOException {
        int bufferSize = 1024;
        byte byteInput[] = new byte[bufferSize];
        int size = 0;
        if (len != -1) {
            long askSize = 0;
            while (len > 0) {
                askSize = (len < (long) bufferSize) ? len : (long) bufferSize;
                if ((size = dis.read(byteInput, 0, (int) askSize)) != -1) {
                    len -= size;
                    buffer.write(byteInput, 0, size);
                } else {
                    break;
                }
            }
        } else {
            // if the content-length is not available
            while ((size = dis.read(byteInput, 0, bufferSize)) != -1) {
                buffer.write(byteInput, 0, size);
            }
        }
    }

    /**
     * Allow caller to insert its own code during the HTTP downloading process by breaking connect/read/disconnect into
     * pieces.
     * 
     * We support basic HTTP authentication, such as http://username:password@web.site
     * 
     * @param url
     * @param method
     * @param contentType
     * @param accept
     * @return
     * @throws Exception
     * @throws NoGatewayException
     */
    HttpURLConnection getOpenedConnection(String url, final String method, final String contentType,
            final String accept, Object requestStr) throws NoGatewayException, Exception {
        // Parse URL to extract user name and password, if applicable.

        URL connector = new URL(url);
        int idx1, idx2;
        String credential = null;
        if ((idx1 = url.indexOf('@')) != -1) {
            idx2 = url.indexOf("://");
            if (idx2 == -1)
                idx2 = 0;
            else
                idx2 += 3;
            credential = "Basic " + Base64.encode(url.substring(idx2, idx1).getBytes());
            String realUrl = "http://";
            realUrl += url.substring(idx1 + 1);
            url = realUrl;
        }
        String host = null;
        String query = null;
        if (CONNECTYPE == 1) { // if (isCMWAP_ != 1) { // CMWAP
            host = url;
            int startIndex = host.indexOf("//") + 2;
            int endIndex = host.indexOf('/', startIndex);
            if (endIndex > 0)
                host = host.substring(startIndex, endIndex);
            int index = url.indexOf('/', startIndex);
            query = url.substring(index);
            Utils.printOutToConsole("~~~~~~~~~~~~~~~~~~CMWAP~~~~~~~~~~~~~~~~~~~~~");

        }
        if (CONNECTYPE == 0) { // if (isCMWAP_ == 1) { // CMNET
            hc_ = (HttpURLConnection) connector.openConnection();
            Utils.printOutToConsole("~~~~~~~~~~~~~~~~~~CMNET~~~~~~~~~~~~~~~~~~~~~");
        } else { // CMWAP
            connector = new URL("http://10.0.0.172:80".concat(query));
            hc_ = (HttpURLConnection) connector.openConnection();
            Utils.printOutToConsole("~~~~~~~~~~~~~~~~~~CMWAP~~~~~~~~~~~~~~~~~~~~~");
        }
        if (hc_ != null) {
            isReachable_ = true;
        }
        if (credential != null)
            hc_.setRequestProperty("Authorization", credential);
        if (CONNECTYPE == 1) // if (isCMWAP_ != 1)
            hc_.setRequestProperty("X-Online-Host", host);
        hc_.setRequestMethod(method);
        // Accept
        String apt = null;
        if (accept == null) {
            // request wml
            apt = "text/vnd.wap.wml";
        } else {
            apt = accept;
        }
        hc_.setRequestProperty("Accept", apt);
        Utils.printOutToConsole("request Accept ---> " + apt);
        hc_.setRequestProperty("User-Agent", Utils.makeUserAgent(Utils.getVersionName(activity_)));
        // hc.setRequestProperty("Cache-Control","no-store");
        // hc.setRequestProperty("Cache-Control", "no-cache");
        // hc.setRequestProperty("Cache-Control", "no-transform");
        hc_.setRequestProperty("Pragma", "no-cache");
        hc_.setRequestProperty("Connection", "Keep-Alive");
        hc_.setRequestProperty("Proxy-Connection", "Keep-Alive");
        if (!Utils.SONY_ERICSSON) {
            // 该处标志需不需要服务端加压�?
            // If it is sony ericsson we don't use gzip,deflate.
            // hc.setRequestProperty("Accept-Encoding", "gzip,deflate");
        }
        // content type.
        if (method.equals(POST)) {
            // Don't need to set content-type for get.
            // symbian plat have problem for this.
            String ct = null;
            if (contentType == null) {
                ct = "application/x-www-form-urlencoded";
            } else {
                ct = contentType;
            }
            hc_.setRequestProperty("Content-Type", ct);
            Utils.printOutToConsole("request Content-Type ---> " + ct);
        }
        if (COOKIE != null) {
            hc_.setRequestProperty("X-Emp-Cookie", COOKIE);
            hc_.setRequestProperty("Cookie", COOKIE);// 多加一个，防止后台的人员修改成cookie.

        }
        if (requestStr != null && ClientHello.clientHmacKey_ != null) {
            String hmacStr = HMac.encryptHMAC((String) requestStr, ClientHello.clientHmacKey_, HMac.KEY_MAC_SHA1);
            hc_.setRequestProperty("X-Emp-Signature", hmacStr);
        }
        hc_.setConnectTimeout(30*1000); // 设置联网超时时间
        hc_.setReadTimeout(60*1000); // 设置读取超时时间
        Utils.printOutToConsole("request cookie ---> " + COOKIE);
        return hc_;
    }

    // 设置项目中额外添加�??头属�?
    private void getPropertyFromOutside(HttpURLConnection hc) {
        // TODO Auto-generated method stub
        if (null != headName_ && headName_.size() > 1) {
            final int size = headName_.size();
            String name = "";
            String value = "";
            for (int i = 0; i < size; i++) {
                name = (String) headName_.elementAt(i);
                value = (String) headValue_.elementAt(i);
                hc.setRequestProperty(name, value);
            }
        }
    }

    public byte[] read(String url, ByteArrayOutputStream buffer, WaitDialog.Task task) throws IOException,
            NoGatewayException {
        InputStream dis = null;
        byte[] resultByts = null;
        try {
            if (task != null && task.stop_)
                throw new CancelIOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
            String contentType = null;
            // 这里最多尝试两次，两次后即使还是移动收费提示页我们也返�?
            int times = 2;
            do {
                times--;
                if (hc_ != null)
                    hc_.disconnect();
                hc_ = connect(url, null, this.GET);
                if (task != null && task.stop_)
                    throw new CancelIOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
                int res = hc_.getResponseCode();

                Utils.printOutToConsole("ResponseCode--->" + res);
                if (res != hc_.HTTP_OK)
                    throw new IOException("无法连接服务器！");
                contentType = hc_.getHeaderField("Content-Type");
            } while (times > 0
                    && contentType != null
                    && (contentType.indexOf("text/vnd.wap.wml") != -1 || contentType
                            .indexOf("application/vnd.wap.wmlc") != -1));

            // Check the Content-Length first
            long len = hc_.getContentLength();
            if (task != null)
                task.setTotalSize((int) len);
            // 允许使用Input
            if (!hc_.getDoInput())
                hc_.setDoInput(true);
            dis = hc_.getInputStream();
            if (task != null && task.stop_)
                throw new CancelIOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
            readByByte(dis, len, buffer, task);
            resultByts = buffer.toByteArray();
            // unZip the result.
            // 如果响应头中带着gzip标识，就必须进行解压否则将会导致界面无法显示或者图片出不来
            String gzip = hc_.getHeaderField("Content-Encoding");
            if (gzip == null) {
                gzip = "not gzip";
            }
            Utils.printOutToConsole("encodeing gzip---->" + gzip);
            if (gzip != null && gzip.trim().equals("gzip")) {
                resultByts = Utils.gunzip(resultByts);
            }
        } catch (CancelIOException cancel) {
            Utils.printException(cancel);
        } catch (SecurityException se) {
            Utils.printException(se);
            throw new IOException("通信异常，请检查您的网络设置及通讯情况，同时确认您的手机是否允许使用网络");
        } catch (ConnectException cf) {
            Utils.printException(cf);
            throw new IOException("对不起您的网络不可用，请稍后重试");
        } catch (Exception ioe) {
            Utils.printException(ioe);
            throw new IOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
        } catch (Error err) {
            Utils.printOutToConsole(err.toString());
            throw new IOException("系统资源不足，退出重新登录可缓解这个问题.");
        } finally {
            try {
                if (dis != null)
                    dis.close();
                if (hc_ != null)
                    hc_.disconnect();
            } catch (IOException ignored) {
                Utils.printException(ignored);
            }
        }
        return resultByts;
    }

    public HttpURLConnection getHttpConnection(String url, String requestStr, String method) throws NoGatewayException,
            Exception {
        HttpURLConnection httpURLConnection = connect(url, requestStr, method);
        return httpURLConnection;
    }

    /**
     * Allow caller to insert its own code during the HTTP downloading process by breaking connect/read/disconnect into
     * pieces.
     * 
     * We support basic HTTP authentication, such as http://username:password@web.site
     */
    HttpURLConnection connect(String url, String requestStr, String method) throws Exception, NoGatewayException {
        // Parse URL to extract user name and password, if applicable.
        URL connector = new URL(url);
        int idx1, idx2;
        String credential = null;
        if ((idx1 = url.indexOf('@')) != -1) {
            idx2 = url.indexOf("://");
            if (idx2 == -1)
                idx2 = 0;
            else
                idx2 += 3;
            credential = "Basic " + Base64.encode(url.substring(idx2, idx1).getBytes());
            String realUrl = "http://";
            realUrl += url.substring(idx1 + 1);
            url = realUrl;
        }
        String host = null;
        String query = null;
        if (CONNECTYPE == 1) { // if (isCMWAP_ != 1) { // CMWAP
            host = url;
            int startIndex = host.indexOf("//") + 2;
            int endIndex = host.indexOf('/', startIndex);
            if (endIndex > 0)
                host = host.substring(startIndex, endIndex);
            int index = url.indexOf('/', startIndex);
            query = url.substring(index);
        }
        if (CONNECTYPE == 0) { // if (isCMWAP_ == 1) { // CMNET
            hc_ = (HttpURLConnection) connector.openConnection();
        } else { // CMWAP
            connector = new URL("http://10.0.0.172:80".concat(query));
            hc_ = (HttpURLConnection) connector.openConnection();
        }
        if (credential != null)
            hc_.setRequestProperty("Authorization", credential);
        if (CONNECTYPE == 1) // if (isCMWAP_ != 1)
            hc_.setRequestProperty("X-Online-Host", host);
        hc_.setRequestMethod(method);
        hc_.setRequestProperty("Accept", "text/vnd.wap.wml"); // request wml
        // 由于wap会屏蔽掉User-Agent属性，导致客户端在使用神州行卡连接时不能顺利登录客户端，所以改成Android-Version属性解决该问题
        hc_.setRequestProperty("Android-Version", Utils.makeUserAgent(Utils.getVersionName(activity_)));
        hc_.setRequestProperty("Pragma", "no-cache");
        hc_.setRequestProperty("Connection", "Keep-Alive");
        hc_.setRequestProperty("Proxy-Connection", "Keep-Alive");
        // If it is sony ericsson we don't use gzip,deflate.
        if (!Utils.SONY_ERICSSON)
            hc_.setRequestProperty("Accept-Encoding", "gzip,deflate");
        if (method.equals(this.POST)) // Don't need to set content-type for get.
            // symbian plat have problem for this.
            hc_.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        if (COOKIE != null) {
            hc_.setRequestProperty("X-Emp-Cookie", COOKIE);
            hc_.setRequestProperty("Cookie", COOKIE);// 多加一个，防止后台的人员修改成cookie.
        }
        if (requestStr != null && ClientHello.clientHmacKey_ != null) {
            String hmacStr = HMac.encryptHMAC(requestStr, ClientHello.clientHmacKey_, HMac.KEY_MAC_SHA1);
            hc_.setRequestProperty("X-EMP-Signature", hmacStr);
        }
        return hc_;
    }

    public void closeConnection(HttpURLConnection hc) throws IOException {
        if (hc != null) {
            hc.disconnect();
        }
    }

    public void setCookie(String cookie) {
        COOKIE = cookie;
    }

    public void cancel() {
        if (null != hc_) {
            hc_.disconnect();
        }
    }

    public String cookie() {
        return COOKIE;
    }

    public void setGetType() {
        httpconnectType_ = HttpManager.GET;
    }

    public void setPostType() {
        httpconnectType_ = HttpManager.POST;
    }

    public void setRequestProperty(String name, String value) {
        if (null == name)
            name = "";
        if (null == value)
            value = "";
        headName_.add(name);
        headValue_.add(value);
    }

    private String addSerialNData(String body) {
        String result = null;
        if (body != null) {
            serialN_ += 1;
            byte[] byt = new byte[8];
            for (int i = 0; i < 8; i++) {
                byt[i] = (byte) (serialN_ >> (56 - i * 8));
            }
            String serN = Base64.encode(byt);
            result = serN + body;
        }
        return result;
    }

    private String addHead(String url) {
        if (url.indexOf("?") == -1) {
            url = url.concat("?");
        }
        if (url.endsWith("?"))
            url = url.concat("app=").concat(APPNAME);
        else
            url = url.concat("&app=").concat(APPNAME);
        url = url.concat("&o=".concat(OPLATFORM));
        return url;
    }

    public Object sendPostRequest(String url, String body, String contentType, String accept) {
        // TODO Auto-generated method stub
        isGetWML_ = false;
        Object resultObj = null;
        try {
            if (body == null) {
                resultObj = sendHttpRequest(url, null, GET, null, null);
            } else {
                resultObj = sendHttpRequest(url, body, POST, contentType, accept);
            }
        } catch (NoGatewayException e) {
            // TODO Auto-generated catch block
            Utils.printException(e);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            Utils.printException(e);
        }
        return resultObj;
    }

    /**
     * @param url
     * @param requestBody
     * @param method
     * @param contentType
     * @param accept
     * @param task
     * @return
     * @throws Exception
     * @throws NoGatewayException
     */
    public Object sendHttpRequest(String url, Object requestBody, String method, String contentType, String accept,
           Map<String,String> headers, WaitDialog.Task task) throws Exception, NoGatewayException {
    	if(!Utils.isConnectByNet()){
    		throw new Exception("当前网络不可用，请稍后再试!");
    	}
        OutputStream dos = null;
        InputStream dis = null;
        // InputStreamReader dir = null;
        Object resultObj = null;
        String result = null;
        String encrypted = null;

        errorStr = null;
        errorType = null;
        errorContent = null;
        // 单元测试不需要此项
        if (!BaseView.UNITTESTFLAG) {
            url = addHead(url);
        }
        Utils.printOutToConsole("url-->" + url);
        try {
            // 修正防重放功能限制条件，只有通过加密通道以后才能执行防重放

            if (url != null && ClientHello.CLIENT_KEY_EXCHANGE != null && ClientHello.CLIENT_FACILITY_HELLO != null
                    && ClientHello.CLIENT_HELLO != null && !url.contains(ClientHello.CLIENT_KEY_EXCHANGE)
                    && !url.contains(ClientHello.CLIENT_FACILITY_HELLO) && !url.contains(ClientHello.CLIENT_HELLO)
                    && (ClientHello.getText() != null && !ClientHello.getText().equals(""))) {
                if (requestBody instanceof String) {
                    requestBody = addSerialNData((String) requestBody);
                }
            }

            // Open up a http connection with the Web server
            // for both send and receive operations
            if (task != null && task.isStop())
                throw new CancelIOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
            String ct = null;
            int respCode = 0;
            // 这里?��?��尝试两次，两次后即使还是移动收费提示页我们也返回。对于取wml内容�? 此处不处理，取完内容后再处理�?
            // 在这里不比较是否是使用cmwap接入点，考虑到有些手机使用直连也能通过cmwap, 但却得到收费提示页�?
            int times = 2;
            do {
                times--;
                try {
                    if (dos != null)
                        dos.close();
                    if (hc_ != null)
                        hc_.disconnect();
                } catch (IOException ignored) {
                    Utils.printException(ignored);
                }
                hc_ = getOpenedConnection(url, method, contentType, accept, requestBody);
                if (task != null && task.isStop())
                    throw new CancelIOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
                if (headers != null && headers.size() > 0) {
                    Iterator it = headers.entrySet().iterator();
                    while (it.hasNext()) {
                        Map.Entry e = (Map.Entry) it.next();
                        String key = (String) e.getKey();
                        if(key == null)
                            continue;
                        String value = (String) e.getValue();
                        hc_.setRequestProperty(key, value);
                    }
                }
                // Send the string entered by user byte by byte
                if (requestBody != null) {
                    byte[] body = null;
                    if (requestBody instanceof String) {
                        body = ((String) requestBody).getBytes("UTF-8");
                    } else {
                        body = (byte[]) requestBody;
                    }
                    hc_.setRequestProperty("Content-Length", "" + body.length);
                    // 允许output操作
                    hc_.setDoOutput(true);
                    dos = hc_.getOutputStream();
                    dos.write(body);
                } else {
                    hc_.setRequestProperty("Content-Length", "0");
                }
                if (task != null && task.isStop()) {
                    throw new CancelIOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
                }
                if (null == hc_)
                    throw new IOException("通信异常，请检查手机的网络设置及通讯情况!");
                respCode = hc_.getResponseCode();
                responseCode_ = respCode;
                String digHmac = hc_.getHeaderField("X-Emp-Signature");
                Utils.printOutToConsole("ResponseCode--->" + respCode);
                if(respCode!=HttpURLConnection.HTTP_OK){
                	throw new NoGatewayException("无法连接服务器！");
                }
                if(null != digHmac && digHmac.equalsIgnoreCase("APP-Upgrading")){
                	isAppUpgrading = true;
                	return null;
                } else if (respCode != HttpURLConnection.HTTP_OK) {
                    throw new NoGatewayException("无法连接服务器！");
                }
                ct = hc_.getHeaderField("Content-Type");
            } while (times > 0 && !isGetWML_ && ct != null
                    && (ct.indexOf("text/vnd.wap.wml") != -1 || ct.indexOf("application/vnd.wap.wmlc") != -1));

            // 允许使用input
            // hc.setDoInput(true);待议，该方法同一个对象只要调用一次即可，调用多次会�?�发异常
            dis = hc_.getInputStream();
            long len = hc_.getContentLength(); // we can't use dis.available().
            if (task != null) {
                task.setTotalSize((int) len);
            }
            ByteArrayOutputStream buffer = new ByteArrayOutputStream(1024);
            readByByte(dis, -1, buffer, task);
            byte[] resultByts = buffer.toByteArray();
            buffer.close();
            // unZip the result.
            String gzip = hc_.getHeaderField("Content-Encoding");
            if (gzip == null) {
                gzip = "not gzip";
            }
            Utils.printOutToConsole("encodeing gzip---->" + gzip);
            if (gzip != null && gzip.trim().equals("gzip")) {
                resultByts = Utils.gunzip(resultByts);
            }

//            if (resultByts != null && ClientHello.serverHmacKey_ != null) {
//                byte[] hmacData = HMac.encryptHMAC(resultByts, ClientHello.serverHmacKey_, HMac.KEY_MAC_SHA1);
//                String orgHmac = Base64.encode(hmacData);
//                String digHmac = hc_.getHeaderField("X-Emp-Signature");
//                // 当该头属性包含文字是超时信息时，不显示hmac错误
//                if (null != digHmac && digHmac.equalsIgnoreCase("timeout")) {
//                    isTimeout = true;
//                } else if (digHmac == null || !digHmac.equals(orgHmac)) {
//                    throw new VerifyException("数据接收不完整，请重试！");
//                }
//            }

            Utils.printOutToConsole("response Content-Type ---> " + ct);
            if (ct.equals(MIME_ARC)) {
                resultObj = resultByts;
            } else {
                result = new String(resultByts, "UTF-8").trim();
                resultObj = result;
            }
            if (task != null && task.isStop()) {
                throw new CancelIOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
            }
        }
     catch(SocketTimeoutException e){
    	 Utils.printOutToConsole("连接超时");
    	 throw new SocketTimeoutException("网络繁忙，请稍后重试!");
     }catch (CancelIOException cancel) {
            Utils.printException(cancel);
        } catch (VerifyException ve) {
            throw ve;
        } catch (SecurityException se) {
            Utils.printException(se);
            String temp = "通信异常，请检查您的网络设置及通讯情况，同时确认您的手机是否允许使用网络";
            throw new NoGatewayException(temp);
        } catch (ConnectException cf) {
            Utils.printException(cf);
            throw new IOException("网络繁忙，请稍后重试!");
        } catch (Exception ioe) {
            Utils.printException(ioe);
            if (null != ioe.getMessage()) {
                if (ioe.getMessage().toLowerCase().indexOf("hmac") != -1) {
                    throw new IOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
                } else if (ioe.getMessage().contains("CDATA")) {
                    // 表示服务端传过来的为错误信息,代替以前的error错�??信息节点
                    throw new IOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
                } else {
                    String temp = Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError");
                    throw new IOException(temp);
                }
            }
        } catch (Error err) {
            Utils.printOutToConsole(err.toString());
            String temp = "系统资源不足，退出重新登录可缓解这个问题.";
            throw new Exception(temp);
        } finally {
            // Free up i/o streams and http connection
            try {
                // if (dir != null) dir.close();
                if (dis != null)
                    dis.close();
                if (dos != null)
                    dos.close();
                if (hc_ != null)
                    hc_.disconnect();
            } catch (IOException ignored) {
                Utils.printException(ignored);
            }
        }
        if (null != result && result.indexOf("<error") != -1) {
//          String error = Utils.getXMLResponseAttribute(result, "string=\"", 0, Utils.MATCH);
//
//          errorStr = error;
//          errorType = Utils.getXMLResponseAttribute(result, "type=\"", 0, Utils.MATCH);
//          errorContent = Utils.getXMLResponseAttribute(result, "content=\"", 0, Utils.MATCH);
          throw new Exception(result);
      }

        return resultObj;

    }

    private void readByByte(InputStream dis, long len, ByteArrayOutputStream buffer, WaitDialog.Task task)
            throws IOException, Exception, Error {
        int bufferSize = 512;
        byte byteInput[] = new byte[bufferSize];
        int size = 0;
        if (len != -1) {
            long askSize = 0;
            while (len > 0) {
                askSize = (len < (long) bufferSize) ? len : (long) bufferSize;
                if ((size = dis.read(byteInput, 0, (int) askSize)) != -1) {
                    len -= size;
                    if (task != null)
                        task.updateFinish(size);
                    buffer.write(byteInput, 0, size);
                } else {
                    break;
                }
                if (task != null && task.isStop())
                    throw new CancelIOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
            }
        } else {
            // if the content-length is not available
            while ((size = dis.read(byteInput, 0, bufferSize)) != -1) {
                buffer.write(byteInput, 0, size);
                if (task != null && task.isStop())
                    throw new CancelIOException(Utils.getConfigStringFormAsset(Utils.getActivity(), "httpError"));
            }
        }
    }
}
